#include <brpc/channel.h>
#include <thread>
#include "main.pb.h"

//brpc是同步调用还是异步调用, 是客户端来决定的  -- 明天ai问一下

void callback(brpc::Controller* cntl, ::example::EchoResponse* response){
    std::unique_ptr<brpc::Controller> cntl_guard(cntl);
    std::unique_ptr<example::EchoResponse> resp_guard(response);
    if (cntl->Failed() == true) {
        std::cout << "Rpc调用失败: " << cntl->ErrorText() << std::endl;
        return;
    }
    std::cout << "收到响应: " << response->message() << std::endl;
}

int main(int argc, char* argv[])
{
    //1. 构造Channel信道, 连接服务器
    brpc::ChannelOptions options;
    options.connect_timeout_ms = -1;    //连接等待超时时间, -1表示一直等待
    options.timeout_ms = -1;        //rpc请求等待超时时间, -1表示一直等待
    options.protocol = "baidu_std"; //序列化协议, 默认使用baidu_std
    brpc::Channel channel;  //为什么要有这个类? 没有这个类就不能进行通信, 理解为管道 
    int ret = channel.Init("127.0.0.1:8080", &options); //参数1: 服务器地址  参数2: 客户端连接时的配置
    if (ret == -1) {
        std::cout << "初始化信道失败! \n";
        return -1;
    }

    //2. 构造EchoService_Stub对象, 用于进行rpc调用
    example::EchoService_Stub stub(&channel);   //相当于客户端类
    //3. 进行Rpc调用
    example::EchoRequest req;
    req.set_message("你好~比特~!");


    //这个Controller提供了很多功能, 其中一个就是辨别返回值的成功或失败
    brpc::Controller* cntl = new brpc::Controller();
    //如果我们不想同步处理, 即不想等待响应, 希望异步, 就要通过Controller设置回调函数
    //注意一个问题: 可能在处理回调函数的时候，如果这个cntl和rsp是栈对象 这个cntl，rsp会被释放掉, 如果这个main函数
    //是一个普通的函数，则处理这个回调函数的时候，可能这个函数已经结束了, 这个cntl，rsp已经被释放掉了，这就可能出现错误

    example::EchoResponse* rsp = new example::EchoResponse();  //用于接收返回值的
    auto clusure = google::protobuf::NewCallback(callback, cntl, rsp);
    stub.Echo(cntl, &req, rsp, clusure);    //异步调用
    // stub.Echo(cntl, &req, rsp, nullptr);      //最后一个参数, 如果是异步调用, 则要传参让服务器设置去run, 我们是同步调用, 所以就不用设置了
    // if(cntl->Failed() == true) {
    //     std::cout << "Rpc调用失败: " << cntl->ErrorText() << std::endl;
    //     return -1;
    // }
    // std::cout << "收到响应: " << rsp->message() << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 0;   //如果是异步调用, 主函数需要等待, 否则程序可能会直接结束
}